package util;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintStream;
import java.util.Vector;

import javax.swing.JOptionPane;

import model.CFCQuery;
import model.CFCRank;
import view.FileChooser;

public class CFC
{

	private File root; // diretorio raiz
	private String path; // diretorio onde serao gravados os arquivos gerados
	private String queryfile;
	private Vector<CFCQuery> querys;
	//private Vector<CFCQuery> rewQueries;
	//private Vector<CFCQuery> colleguesQueries;
	//private Vector<CFCQuery> postDocsQueries;
	//private Vector<CFCQuery> jbwQueries;

	public CFC()
	{
		querys = new Vector<CFCQuery>();
		
		//rewQueries = new Vector<CFCQuery>();
		//colleguesQueries = new Vector<CFCQuery>();
		//postDocsQueries = new Vector<CFCQuery>();
		//jbwQueries = new Vector<CFCQuery>();
	}
	
	public String getQueryfile()
	{
		return this.queryfile;
	}

	public void setQueryfile(String queryfile)
	{
		this.queryfile = queryfile;
	}

	public File getRoot()
	{
		return this.root;
	}

	public void setRoot(File root)
	{
		this.root = root;
	}

	public String getPath()
	{
		return this.path;
	}

	public void setPath(String path)
	{
		this.path = path;
	}

	public void scanDirCFC(File dir)
	{
		
		path = dir.getAbsolutePath() + "/parsed";
		File diretorio = new File(path);

		// Tenta criar diretorio arquivosSeparados
		if (!diretorio.isDirectory())
		{
			if (!diretorio.mkdir())
			{
				JOptionPane.showMessageDialog(null,"Error: Could not create 'parsed' directory! The files will be created in the main directory.","Error",JOptionPane.ERROR_MESSAGE);
				path = dir.getAbsolutePath(); // diretorio sem o /parsed, o raiz.
			}
		}

		// Comeca a varrer os arquivos do diretorio
		for (File file : dir.listFiles())
		{
			if (file.isFile())
			{
				parseFile(file);
			}
		}
		
	}

	private void parseFile(File arq)
	{

		FileOutputStream arquivoGerado = null;
		PrintStream printer = null;
		BufferedReader bf;

		try
		{

			bf = new BufferedReader(new FileReader(arq));

			String linha;
			String temporario = "";
			String nomeArquivoGerado;

			while ((linha = bf.readLine()) != null)
			{ // enquanto não fim do arquivo, ler linha após linha

				if (linha.startsWith("PN "))
				{ // Novo arquivo
					temporario = linha; // armazena temporariamente o conteudo da linha pois o nome do novo arquivo está na proxima linha
				}

				else if (linha.startsWith("RN "))
				{

					nomeArquivoGerado = (path + "/file" + linha.substring(4)).trim();

					if (arquivoGerado != null)
						arquivoGerado.close();

					if (printer != null)
						printer.close();

					arquivoGerado = new FileOutputStream(nomeArquivoGerado,false);
					printer = new PrintStream(arquivoGerado,false);

					printer.println(temporario);
					printer.println(linha);

				}
				else if (!linha.startsWith("RN ") && !linha.startsWith("PN "))
				{ // outros dados
					if (printer != null)
						printer.println(linha);
				}
			}

			if (arquivoGerado != null)
				arquivoGerado.close();

			bf.close();

		} catch (FileNotFoundException e)
		{
			e.printStackTrace();
		} catch (IOException e)
		{
			e.printStackTrace();
		}

	}

	public void parseCFCData()
	{

		System.out.println("Initiating CFC files processing...");

		JOptionPane.showMessageDialog(null,"IMPORTANT:\n\n- To improve performance, only CFC files should be inside the choosen directory. Otherwise, time will be wasted processing useless files.\n- Only direct files are considered. Subdirectories will not be processed.","Warning",JOptionPane.INFORMATION_MESSAGE);

		// Setting up the graphic interface
		FileChooser fc = new FileChooser();
		String directory = fc.getDBDirectory();

		if (directory == null)
		{
			JOptionPane.showMessageDialog(null,"Operation cancelled!","Cancel",JOptionPane.INFORMATION_MESSAGE);
			System.exit(0);
		}

		root = new File(directory);

		if (root.isDirectory())
		{
			scanDirCFC(root);
		}
		else
			JOptionPane.showMessageDialog(null,"Invalid directory!","INFO",JOptionPane.INFORMATION_MESSAGE);

		System.out.println("CFC files processing finished!");
	}

	@SuppressWarnings("static-access")
	public Vector<CFCQuery> parseQueryFile()
	{
		// Setting up the query file
		Vector<String> stopwords = (new Read()).getStopWords();
		FileChooser fc = new FileChooser();
		String file = fc.getQueryFile();
		
		if (file == null)
		{
			JOptionPane.showMessageDialog(null,"Operation cancelled!","Cancel",JOptionPane.INFORMATION_MESSAGE);
			System.exit(0);
		}
		

		this.queryfile = file;
		
		//Parsing query file
		
		BufferedReader bf;

		try
		{

			bf = new BufferedReader(new FileReader(this.queryfile));

			@SuppressWarnings("unused")
			Vector<CFCQuery> querys = new Vector<CFCQuery>();
			CFCQuery q = null;

			@SuppressWarnings("unused")
			boolean moreLines = false;
			boolean moreLinesQU = false;
			boolean newQuery = true;
			String linha;

			while ((linha = bf.readLine()) != null)
			{ 

				//System.out.println("#############\n LINHA: " + linha + "\n ############");
							
				if(newQuery)
				{
					q = new CFCQuery();
					newQuery = false;
				}
				
				if (linha.startsWith("QN"))// Nova Query
				{ 
					//System.out.println("QN...");
					int number = Integer.parseInt((linha.split(" "))[1]);
					q.setNumber(number);
				}
				else if (linha.startsWith("QU"))// Query
				{
					
					//System.out.println("QU...");
					linha = linha.substring(3);
					q.setString(linha);
					
					while( (linha = bf.readLine()).startsWith("   ") )
					{
						moreLinesQU = true;
						q.setString(q.getString() + linha.substring(2));	
						bf.mark(linha.length() + 2);
					}

					if(moreLinesQU)
					{
						bf.reset();
						moreLinesQU = false;
					}
					
				}
				else if (linha.startsWith("NR"))// Numero de documentos retornados
				{ 
					//System.out.println("NR...");
					int numberOfDocuments = Integer.parseInt((linha.split(" "))[1]);
					q.setNumberOfDocuments(numberOfDocuments);
				}
				else if (linha.startsWith("RD"))// Lista e ranking dos documentos retornados
				{
				
					//System.out.println("RD... : " + q.getNumber());
					
					String[] dados;
					int documentNumber = 0;
					int rew = 0; 
					int collegues = 0;
					int postDocs = 0;
					int jbw = 0;

					linha = linha.substring(3);
					
					while(linha.charAt(0) == ' ')
					{
						linha = linha.substring(1);
					}
									
					dados = linha.split("\\s+");
					
					for(int k=0; k < dados.length; k++)
					{
						//System.out.println("Lido: '" + dados[k] + "'" );

						if(k%2 == 0)
						{
							documentNumber = Integer.parseInt(dados[k]);
							//System.out.println("Documento: " + documentNumber);							
						}
						else
						{
							rew = Integer.parseInt(dados[k].substring(0,1));
							collegues = Integer.parseInt(dados[k].substring(1,2));
							postDocs = Integer.parseInt(dados[k].substring(2,3)); 
							jbw = Integer.parseInt(dados[k].substring(3,4));

							q.addRankingEntry(documentNumber, rew , collegues, postDocs, jbw);
						}

					}
					
					while( (linha = bf.readLine()).startsWith("   ") && linha.trim().length() > 0)
					{
						//System.out.println("Query: " + q.getNumber() +  "\n############# LINHA: " + linha + " ############");
						
						moreLines = true;
						
						//System.out.println("Second turn...");
						
						linha = linha.substring(3);
						
						while(linha.charAt(0) == ' ')
						{
							linha = linha.substring(1);
						}
						
						dados = linha.split("\\s+");
						
						for(int k=0; k < dados.length; k++)
						{
							
							if(k%2 == 0)
							{
								documentNumber = Integer.parseInt(dados[k]);	
							}
							else
							{
								rew = Integer.parseInt(dados[k].substring(0,1));
								collegues = Integer.parseInt(dados[k].substring(1,2));
								postDocs = Integer.parseInt(dados[k].substring(2,3)); 
								jbw = Integer.parseInt(dados[k].substring(3,4));

								q.addRankingEntry(documentNumber, rew , collegues, postDocs, jbw);
							}
							
						}
						
						bf.mark(linha.length() + 2);
					}
				
					if(moreLines)
					{
						bf.reset();
						moreLines = false;
					}
					
					String newString = "";
					for(String s : q.getString().split("\\s+"))
					{
						if(!stopwords.contains(s))
							newString += s + " "; 
					}
					q.setString(newString.trim().replaceAll("?",""));
					
					this.querys.add(q);
					newQuery = true;
				}

				//System.out.println("QueryNumber: " + q.getNumber());
			}

			bf.close();

		} catch (FileNotFoundException e)
		{
			e.printStackTrace();
		} catch (IOException e)
		{
			e.printStackTrace();
		}
		
		return this.querys;
	}

	public String[] getRD(int qn, int e)
	{
		Vector<String> lista = new Vector<String>();
		//Vector<CFCQuery> consultas = null;
		
				for(CFCQuery q : this.querys)
		{
			if(q.getNumber() == qn)
			{
				System.out.println("Query: " + q.getString());
				for(CFCRank r : q.getRanking())
				{
					if( (e == 1) && (r.getRew() > 0) ) lista.add("" + r.getDocument()); 
					else if( (e == 2) && (r.getColleagues() > 0) ) lista.add("" + r.getDocument());
					else if( (e == 3) && (r.getPostDocs() > 0) ) lista.add("" + r.getDocument());
					else if( (e == 4) && (r.getJbw() > 0) ) lista.add("" + r.getDocument());
				}
				
				break;
			}
		}
				
		return lista.toArray(new String[lista.size()]);
	}
}
